package com.hxk.createMode.singleton;

import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.lang.reflect.Constructor;
import java.util.concurrent.CountDownLatch;
/**
 * 单例模式测试
 * 场景：
 * 	保证一个类只有一个实例，并且提供一个访问该实例的全局访问点。
 * 选择：
 * 单例对象 占用 资源 少，不需要 延时加载：
	• 枚举式 好于 饿汉式
  – 单例对象 占用 资源 大，需要 延时加载：
	• 静态内部类式 好于 懒汉式
 * @author Cactus
 */
public class TestSingleton {

	public static void main(String[] args) throws Exception {
		//单例测试
		singleTest();
		//反射破解单例（饿汉式、懒汉式、静态类式、双重检锁）
		reflectTest();
		//通过反序列化破解单例（饿汉式、懒汉式、静态类式、双重检锁）
		unSerializableTest();
		//单例性能测试
		performanceTest();
	}
	/**
	 * 单例性能测试
	 * @throws InterruptedException
	 */
	private static void performanceTest() throws InterruptedException {
		int threadNum = 10;
		long start = System.currentTimeMillis();
		final CountDownLatch latch = new CountDownLatch(threadNum);
		for(int n = 0; n < threadNum; n++) {
			new Thread(new Runnable() {
				@Override
				public void run() {
					for(int i = 0; i < 100000; i++) {
						//Object o = SingletonDemo1.getInstance();//饿汉式=12
						//Object o = SingletonDemo2.getInstance();//懒汉式=44
						//Object o = SingletonDemo3.getInstance();//静态内部类=11
						//Object o = SingletonDemo4.INSTANCE;//枚举=6
						Object o = SingletonDemo5.getInstance();//双重检锁=14
					}
					latch.countDown();
				}
			}).start();
		}
		latch.await();//阻塞main主线程等待
		long end = System.currentTimeMillis();
		System.out.println("总耗时："+(end-start));
	}
	/**
	 * 通过反序列化破解单例（饿汉式、懒汉式、静态类式、双重检锁）
	 * 防止反射破解方式：
	 * 在单例类中加入以下readResolve()方法，代码如下
	 * public Object readResolve() throws ObjectStreamException {
		  return instance;
	   }
	 */
	private static void unSerializableTest() throws Exception {
		SingletonDemo6 ss6 = SingletonDemo6.getInstance();
		SingletonDemo6 ss6_ = SingletonDemo6.getInstance();
		System.out.println(ss6);
		System.out.println(ss6_);
		FileOutputStream fos = new FileOutputStream("d:/obj.txt");
		ObjectOutputStream oos = new ObjectOutputStream(fos);
		oos.writeObject(ss6);
		oos.close();
		fos.close();
		FileInputStream fis = new FileInputStream("d:/obj.txt");
		ObjectInputStream ois = new ObjectInputStream(fis);
		SingletonDemo6 sx = (SingletonDemo6) ois.readObject();
		System.out.println(sx);
		ois.close();
		fis.close();
	}

	/**反射破解单例（饿汉式、懒汉式、静态类式、双重检锁）
	 * 防止反射破解方式：
	 * 在单例类的私有构造器中加入以下代码（以本例用的SingletonDemo6为例）：
	 * private SingletonDemo6() {
			if(instance != null) {
				throw new RuntimeException("本例为单例类，不允许反射实现！");
			}
	   };
	 */
	private static void reflectTest() throws Exception {
		SingletonDemo6 s6 = SingletonDemo6.getInstance();
		SingletonDemo6 s6_ = SingletonDemo6.getInstance();
		System.out.println(s6);
		System.out.println(s6_);
		Class<SingletonDemo6> clazz = (Class<SingletonDemo6>) Class.forName("com.hxk.singleton.SingletonDemo6");
		Constructor<SingletonDemo6> c = clazz.getDeclaredConstructor(null);
		c.setAccessible(true);//允许访问私有方法
		SingletonDemo6 s6x1 = c.newInstance();
		SingletonDemo6 s6x2 = c.newInstance();
		System.out.println(s6x1);
		System.out.println(s6x2);
	}
	/**
	 *单例测试
	 */
	private static void singleTest() {
		//饿汉式
		SingletonDemo1 s1 = SingletonDemo1.getInstance();
		SingletonDemo1 s1_ = SingletonDemo1.getInstance();
		System.out.println(s1 == s1_);
		//懒汉式
		SingletonDemo2 s2 = SingletonDemo2.getInstance();
		SingletonDemo2 s2_ = SingletonDemo2.getInstance();
		System.out.println(s2 == s2_);
		//静态类式
		SingletonDemo3 s3 = SingletonDemo3.getInstance();
		SingletonDemo3 s3_ = SingletonDemo3.getInstance();
		System.out.println(s3 == s3_);
		//枚举式
		SingletonDemo4 s4 = SingletonDemo4.INSTANCE;
		SingletonDemo4 s4_ = SingletonDemo4.INSTANCE;
		System.out.println(s4 == s4_);
		//双重检锁
		SingletonDemo5 s5 = SingletonDemo5.getInstance();
		SingletonDemo5 s5_ = SingletonDemo5.getInstance();
		System.out.println(s5 == s5_);
	}
}
